package com.xh.rufongwallpaper.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xh.rufongwallpaper.common.util.VOConverter;
import com.xh.rufongwallpaper.config.UploadConfig;
import com.xh.rufongwallpaper.entity.Wallpaper;
import com.xh.rufongwallpaper.mapper.WallpaperMapper;
import com.xh.rufongwallpaper.service.CategoryService;
import com.xh.rufongwallpaper.service.WallpaperService;
import com.xh.rufongwallpaper.vo.WallpaperVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.*;

/**
 * 壁纸服务实现类
 *
 * @author XH
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class WallpaperServiceImpl implements WallpaperService {

    private final WallpaperMapper wallpaperMapper;
    private final CategoryService categoryService;
    private final UploadConfig uploadConfig;

    @Override
    public Optional<Wallpaper> getWallpaperById(Long id) {
        return Optional.ofNullable(wallpaperMapper.selectOne(
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getId, id)
                        .eq(Wallpaper::getIsDeleted, false)
        ));
    }

    @Override
    public Page<Wallpaper> getWallpapers(int pageIndex, int pageSize) {
        Page<Wallpaper> page = new Page<>(pageIndex + 1, pageSize);
        return wallpaperMapper.selectPage(page,
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getCreateTime)
        );
    }

    @Override
    public Page<Wallpaper> getWallpapersByCategory(Long categoryId, int pageIndex, int pageSize) {
        Page<Wallpaper> page = new Page<>(pageIndex + 1, pageSize);
        return wallpaperMapper.selectPage(page,
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getCategoryId, categoryId)
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getCreateTime)
        );
    }

    @Override
    public Page<Wallpaper> getWallpapersByTag(String tag, int pageIndex, int pageSize) {
        Page<Wallpaper> page = new Page<>(pageIndex + 1, pageSize);
        return wallpaperMapper.selectPage(page,
                new LambdaQueryWrapper<Wallpaper>()
                        .like(Wallpaper::getTags, tag)
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getCreateTime)
        );
    }

    @Override
    public Page<Wallpaper> searchWallpapers(String keyword, int pageIndex, int pageSize) {
        Page<Wallpaper> page = new Page<>(pageIndex + 1, pageSize);
        return wallpaperMapper.selectPage(page,
                new LambdaQueryWrapper<Wallpaper>()
                        .and(wrapper -> wrapper
                                .like(Wallpaper::getTitle, keyword)
                                .or()
                                .like(Wallpaper::getDescription, keyword)
                                .or()
                                .like(Wallpaper::getTags, keyword))
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getCreateTime)
        );
    }

    @Override
    public Page<Wallpaper> getHotWallpapers(int pageIndex, int pageSize) {
        Page<Wallpaper> page = new Page<>(pageIndex + 1, pageSize);
        return wallpaperMapper.selectPage(page,
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getDownloadCount)
        );
    }

    @Override
    public Page<Wallpaper> getLatestWallpapers(int pageIndex, int pageSize) {
        Page<Wallpaper> page = new Page<>(pageIndex + 1, pageSize);
        return wallpaperMapper.selectPage(page,
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getCreateTime)
        );
    }

    @Override
    public Page<Wallpaper> getTrendingWallpapers(int pageIndex, int pageSize) {
        // 趋势壁纸：结合下载次数和最新时间，算法可以根据业务调整
        Page<Wallpaper> page = new Page<>(pageIndex + 1, pageSize);
        return wallpaperMapper.selectPage(page,
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getDownloadCount)
                        .orderByDesc(Wallpaper::getCreateTime)
        );
    }

    @Override
    @Transactional
    public boolean incrementDownloadCount(Long id) {
        return wallpaperMapper.update(null,
                new LambdaUpdateWrapper<Wallpaper>()
                        .eq(Wallpaper::getId, id)
                        .eq(Wallpaper::getIsDeleted, false)
                        .setSql("download_count = download_count + 1")
        ) > 0;
    }
    
    @Override
    public Wallpaper getRandomWallpaper(Long categoryId) {
        LambdaQueryWrapper<Wallpaper> queryWrapper = new LambdaQueryWrapper<Wallpaper>()
                .eq(Wallpaper::getIsDeleted, false)
                .eq(Wallpaper::getStatus, 1);
        
        if (categoryId != null) {
            queryWrapper.eq(Wallpaper::getCategoryId, categoryId);
        }
        
        // 获取总记录数
        Long count = wallpaperMapper.selectCount(queryWrapper);
        if (count == null || count == 0) {
            return null;
        }
        
        // 随机获取一条记录
        int randomIndex = new Random().nextInt(count.intValue());
        Page<Wallpaper> page = new Page<>(randomIndex + 1, 1);
        Page<Wallpaper> result = wallpaperMapper.selectPage(page, queryWrapper);
        
        return result.getRecords().isEmpty() ? null : result.getRecords().get(0);
    }
    
    @Override
    public List<Wallpaper> getRelatedWallpapers(Long wallpaperId, Long categoryId, int limit) {
        return wallpaperMapper.selectList(
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getCategoryId, categoryId)
                        .ne(Wallpaper::getId, wallpaperId)
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
                        .orderByDesc(Wallpaper::getDownloadCount)
                        .last("LIMIT " + limit)
        );
    }
    
    @Override
    public int countWallpapersByCategory(Long categoryId) {
        return Math.toIntExact(wallpaperMapper.selectCount(
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getCategoryId, categoryId)
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
        ));
    }
    
    @Override
    public boolean existsById(Long id) {
        return wallpaperMapper.exists(
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getId, id)
                        .eq(Wallpaper::getIsDeleted, false)
                        .eq(Wallpaper::getStatus, 1)
        );
    }

    @Override
    @Transactional
    public WallpaperVO uploadWallpaper(MultipartFile file, String title, String description, Long categoryId, String tags) {
        // 验证文件
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }

        // 验证文件类型
        String contentType = file.getContentType();
        if (contentType == null || !uploadConfig.getWallpaper().getAllowedTypesList().contains(contentType)) {
            throw new IllegalArgumentException("不支持的文件类型，仅支持: " + 
                uploadConfig.getWallpaper().getAllowedTypes());
        }

        // 验证文件大小（最大10MB）
        if (file.getSize() > 10 * 1024 * 1024) {
            throw new IllegalArgumentException("文件大小不能超过10MB");
        }

        // 验证分类
        if (!categoryService.existsById(categoryId)) {
            throw new IllegalArgumentException("分类不存在");
        }

        try {
            // 生成文件名
            String originalFilename = file.getOriginalFilename();
            if (originalFilename == null) {
                originalFilename = "image.jpg";
            }
            String extension = originalFilename.contains(".") ? 
                originalFilename.substring(originalFilename.lastIndexOf(".")) : ".jpg";
            String filename = UUID.randomUUID().toString() + extension;

            // 获取配置的上传路径（相对路径）
            String relativeUploadDir = uploadConfig.getWallpaper().getPath();
            // 获取绝对路径
            String absoluteUploadDir = new File(uploadConfig.getBasePath(), relativeUploadDir).getAbsolutePath();
            log.info("上传路径: {}", absoluteUploadDir);
            
            // 确保目录存在
            File dir = new File(absoluteUploadDir);
            if (!dir.exists()) {
                boolean mkdirSuccess = dir.mkdirs();
                if (!mkdirSuccess) {
                    throw new IOException("无法创建上传目录: " + absoluteUploadDir);
                }
            }
            
            // 确保缩略图目录存在
            File thumbnailDir = new File(absoluteUploadDir, "thumbnails");
            if (!thumbnailDir.exists()) {
                boolean mkdirSuccess = thumbnailDir.mkdirs();
                if (!mkdirSuccess) {
                    throw new IOException("无法创建缩略图目录: " + thumbnailDir.getAbsolutePath());
                }
            }
            
            // 保存原始文件（使用绝对路径）
            File destFile = new File(dir, filename);
            file.transferTo(destFile);
            log.info("原始文件已保存: {}", destFile.getAbsolutePath());
            
            // 读取图片获取尺寸
            BufferedImage originalImage = ImageIO.read(destFile);
            if (originalImage == null) {
                throw new IOException("无法读取图片文件");
            }
            
            int imageWidth = originalImage.getWidth();
            int imageHeight = originalImage.getHeight();
            log.info("图片尺寸: {}x{}", imageWidth, imageHeight);

            // 生成缩略图文件路径（使用绝对路径）
            File thumbnailFile = new File(thumbnailDir, filename);
            
            // 生成缩略图
            generateThumbnail(originalImage, thumbnailFile, extension);
            log.info("缩略图已生成: {}", thumbnailFile.getAbsolutePath());

            // 保存到数据库的路径使用相对路径
            String relativeImagePath = relativeUploadDir + "/" + filename;
            String relativeThumbnailPath = relativeUploadDir + "/thumbnails/" + filename;

            // 创建壁纸记录
            Wallpaper wallpaper = new Wallpaper();
            wallpaper.setTitle(title);
            wallpaper.setDescription(description);
            wallpaper.setCategoryId(categoryId);
            wallpaper.setFilePath(relativeImagePath);
            wallpaper.setThumbnailPath(relativeThumbnailPath);
            wallpaper.setWidth(imageWidth);
            wallpaper.setHeight(imageHeight);
            wallpaper.setFileSize(file.getSize());
            wallpaper.setTags(tags);
            wallpaper.setDownloadCount(0);
            wallpaper.setViewCount(0);
            wallpaper.setStatus(1);
            wallpaper.setIsDeleted(false);
            wallpaper.setCreateTime(new Date());
            wallpaper.setUpdateTime(new Date());

            // 保存到数据库
            wallpaperMapper.insert(wallpaper);
            log.info("壁纸记录已保存到数据库: id={}", wallpaper.getId());

            // 转换为VO并返回
            return VOConverter.convertToWallpaperVO(wallpaper);

        } catch (IOException e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
        }
    }

    /**
     * 生成缩略图
     */
    private void generateThumbnail(BufferedImage originalImage, File targetFile, String extension) throws IOException {
        // 确保缩略图目录存在
        if (targetFile.getParentFile() != null && !targetFile.getParentFile().exists()) {
            boolean mkdirSuccess = targetFile.getParentFile().mkdirs();
            if (!mkdirSuccess) {
                throw new IOException("无法创建缩略图目录");
            }
        }

        // 计算缩略图尺寸
        int originalWidth = originalImage.getWidth();
        int originalHeight = originalImage.getHeight();
        int targetWidth = uploadConfig.getWallpaper().getThumbnailWidth();
        int targetHeight = (int) (originalHeight * (targetWidth / (double) originalWidth));

        // 创建缩略图
        BufferedImage thumbnailImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = thumbnailImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);
        g2d.dispose();

        // 保存缩略图，使用配置的质量
        saveImageWithQuality(thumbnailImage, extension, targetFile, uploadConfig.getWallpaper().getThumbnailQuality());
    }
    
    /**
     * 以指定质量保存图片
     */
    private void saveImageWithQuality(BufferedImage image, String formatName, File output, double quality) throws IOException {
        // 提取格式名（不含点）
        if (formatName.startsWith(".")) {
            formatName = formatName.substring(1);
        }
        
        // 对于不支持压缩质量的格式（如GIF），直接使用标准写入
        if (formatName.equalsIgnoreCase("gif")) {
            ImageIO.write(image, formatName, output);
            return;
        }
        
        // 使用质量压缩
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
        if (!writers.hasNext()) {
            throw new IOException("没有找到合适的图片写入器: " + formatName);
        }
        
        ImageWriter writer = writers.next();
        ImageWriteParam writeParam = writer.getDefaultWriteParam();
        
        // 设置压缩模式
        if (writeParam.canWriteCompressed()) {
            writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            writeParam.setCompressionQuality((float) quality);
        }
        
        // 写入图片
        try (OutputStream outputStream = new FileOutputStream(output);
             ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream)) {
            writer.setOutput(imageOutputStream);
            writer.write(null, new IIOImage(image, null, null), writeParam);
            writer.dispose();
        }
    }

    @Override
    public String getWallpaperFilePath(Long id) {
        Wallpaper wallpaper = wallpaperMapper.selectOne(
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getId, id)
                        .eq(Wallpaper::getIsDeleted, false)
        );
        if (wallpaper == null) {
            return null;
        }
        return wallpaper.getFilePath();
    }

    @Override
    public String getWallpaperThumbnailPath(Long id) {
        Wallpaper wallpaper = wallpaperMapper.selectOne(
                new LambdaQueryWrapper<Wallpaper>()
                        .eq(Wallpaper::getId, id)
                        .eq(Wallpaper::getIsDeleted, false)
        );
        if (wallpaper == null) {
            return null;
        }
        return wallpaper.getThumbnailPath();
    }
} 